﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WMM.Tapioca.Linkbase;
using System.Collections;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Linq;

namespace WMM.Tapioca.Taxonomy
{
    /// <summary>
    /// XBRL 2.1 Specification 5.1.3
    /// An encapsulation of the XBRL element "RoleType". 
    /// </summary>
    [Serializable]
    public class RoleType
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// The schema that references this role type.
        /// </summary>
        public XmlSchema Schema
        {
            get;
            private set;
        }

        /// <summary>
        /// The URI for this role.
        /// </summary>
        public Uri RoleUri
        {
            get;
            private set;
        }

        /// <summary>
        /// The ID of this role type.
        /// </summary>
        public string Id
        {
            get;
            private set;
        }

        /// <summary>
        /// The definition of this role type.
        /// </summary>
        public string Definition
        {
            get;
            private set;
        }

        /// <summary>
        /// A collection of "UsedOn" references for this role type. Used to identify what
        /// elements may use a taxonomy defined role or arc role value.
        /// </summary>
        public List<XName> UsedOnReferences
        {
            get;
            private set;
        }


        internal RoleType(XmlSchema containingXbrlSchema, XmlNode roleTypeNode)
        {
            this.Schema = containingXbrlSchema;
            this.UsedOnReferences = new List<XName>();

            try
            {
                this.RoleUri = new Uri(XmlUtilities.GetAttributeValue(roleTypeNode, "roleURI"));
            }
            catch (Exception ex)
            {
                log.Error("Validation error on Uri:", ex);
            }

            this.Id = XmlUtilities.GetAttributeValue(roleTypeNode, "id");

            log.Debug("Creating RoleType: " + this.RoleUri + "-" + this.Id);

            foreach (XmlNode currentChild in roleTypeNode.ChildNodes)
            {
                if (currentChild.LocalName.Equals("definition"))
                {
                    this.Definition = currentChild.InnerText;
                }

                if (currentChild.LocalName.Equals("usedOn"))
                {
                    string valueQN = currentChild.InnerText;

                    string prefix = GetPrefix(valueQN);
                    string name = "";

                    foreach (XmlQualifiedName nameSpace in containingXbrlSchema.Namespaces.ToArray())
                    {
                        if (nameSpace.Name.Equals(prefix))
                        {
                            name = nameSpace.Namespace;
                            break;
                        }
                    }

                    if (name.Length == 0)
                    {
                        name = currentChild.GetNamespaceOfPrefix(prefix);
                    }

                    XNamespace ns = name;
                    XName value = ns + GetLocalName(valueQN);
                    this.UsedOnReferences.Add(value);
                }
            }
        }


        private string GetLocalName(string valueQN)
        {
            string[] dimAttrQN = valueQN.Split(':');

            if (dimAttrQN.Count() > 1)
            {
                return dimAttrQN[1];
            }
            else
            {
                return dimAttrQN[0];
            }

        }


        private string GetPrefix(string valueQN)
        {
            string[] dimAttrQN = valueQN.Split(':');

            if (dimAttrQN.Count() > 1)
            {
                return dimAttrQN[0];
            }
            else
            {
                return "";
            }
        }

    }
}
